package preprocessor;

import java.util.HashSet;
import java.util.Set;

import entities.concept.AndConcept;
import entities.concept.Concept;
import entities.concept.DomainConceptEQ;
import entities.concept.DomainConceptLT;
import entities.concept.DomainConceptLTEQ;
import entities.concept.ExistsConcept;
import entities.concept.Nominal;
import entities.concept.NotConcept;
import entities.concept.OrConcept;
import entities.concept.PConcept;
import entities.concept.UniversalConcept;

/**
 * This class simplifies axioms/concepts
 * 
 * @author j55wu
 * 
 */
public class Simplification {

	public static Set<Concept> NNF(Set<Concept> cs) {
		HashSet<Concept> ret = new HashSet<Concept>();
		for (Concept c : cs) {
			ret.add(NNF(c, false));
		}
		return ret;
	}

	// push the negation inside
	public static Concept NNF(Concept c, boolean hasnot) {
		if (c == null) {
			return null;
		}
		Concept fin = null;
		boolean found = hasnot;
		try {
			if (c instanceof AndConcept) {
				AndConcept and = (AndConcept) c;
				HashSet<Concept> res = new HashSet<Concept>();
				for (Concept ac : and.getConceptSet()) {
					res.add(NNF(ac, found));
				}
				if (found)
					fin = new OrConcept(res);
				else
					fin = new AndConcept(res);
			} else if (c instanceof UniversalConcept) {
				UniversalConcept allres = (UniversalConcept) c;
				if (!found) {
					fin = new UniversalConcept(allres.getRole(), NNF(
							allres.getFiller(), found));
				} else {
					fin = new ExistsConcept(allres.getRole(), NNF(
							allres.getFiller(), found));
				}
			} else if (c instanceof PConcept) {
				PConcept myclass = (PConcept) c;
				if (!found)
					fin = myclass;
				else
					fin = new NotConcept(myclass);
			} else if (c instanceof Nominal) {
				Nominal myclass = (Nominal) c;
				if (!found)
					fin = myclass;
				else
					fin = new NotConcept(myclass);
			} else if (c instanceof OrConcept) {
				OrConcept or = (OrConcept) c;
				HashSet<Concept> res = new HashSet<Concept>();
				for (Concept oc : or.getConceptSet()) {
					res.add(NNF(oc, found));
				}
				if (found)
					fin = new AndConcept(res);
				else
					fin = new OrConcept(res);
			} else if (c instanceof ExistsConcept) {
				ExistsConcept someres = (ExistsConcept) c;
				if (!found) {
					fin = new ExistsConcept(someres.getRole(), NNF(
							someres.getFiller(), found));
				} else {
					fin = new UniversalConcept(someres.getRole(), NNF(
							someres.getFiller(), found));
				}
			} else if (c instanceof NotConcept) {
				NotConcept not = (NotConcept) c;
				fin = NNF(not.getConcept(), !found);
			} else if (c instanceof DomainConceptEQ) {
				DomainConceptEQ<?, ?> dce = (DomainConceptEQ<?, ?>) c;
				if (!found) {
					fin = c;
				} else {
					// ~ f = g is the same as f>g or f<g
					HashSet<Concept> os = new HashSet<Concept>();
					os.add(new DomainConceptLT<Object, Object>(dce.getLHS(),
							dce.getValue()));
					os.add(new DomainConceptLT<Object, Object>(dce.getValue(),
							dce.getLHS()));
					fin = new OrConcept(os);
				}
			} else if (c instanceof DomainConceptLT) {
				DomainConceptLT<?, ?> dce = (DomainConceptLT<?, ?>) c;
				if (!found) {
					fin = c;
				} else {
					// ! f < g is the same as f>=g,
					// HashSet<Concept> os = new HashSet<Concept>();
					// os.add(new DomainConceptEQ<?,?>(dce.getFeature(),
					// dce.getValue()));
					// os.add(new DomainConceptLTEQ(dce.getValue(),
					// dce.getFeature()));
					fin = new DomainConceptLTEQ<Object, Object>(dce.getValue(),
							dce.getLHS());
				}
			} else if (c instanceof DomainConceptLTEQ) {
				DomainConceptLTEQ<?, ?> dce = (DomainConceptLTEQ<?, ?>) c;
				if (!found) {
					fin = c;
				} else {
					// ! f<=g is the same as f>g
					// HashSet<Concept> os = new HashSet<Concept>();
					// os.add(new DomainConceptLT(dce.getValue(),
					// dce.getFeature()));
					fin = new DomainConceptLT<Object, Object>(dce.getValue(),
							dce.getLHS());
				}
			}
			// further extensions go here...
			else {
				System.out
						.println("Items not handle by current NNF algorithm: "
								+ c);
			}
		} catch (Exception err) {
			err.printStackTrace();
		}
		return fin;
	}

}
